package cn.wolfcode.business.service.impl;

import cn.wolfcode.business.domain.BusAppointment;
import cn.wolfcode.business.mapper.BusAppointmentMapper;
import cn.wolfcode.business.service.IBusAppointmentService;
import cn.wolfcode.business.util.DateUtil;
import cn.wolfcode.business.util.RegexUtils;
import cn.wolfcode.business.util.VehiclePlateNoUtil;
import cn.wolfcode.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 养修信息预约Service业务层处理
 * 
 * @author wolfcode
 * @date 2025-09-18
 */
@Service
public class BusAppointmentServiceImpl implements IBusAppointmentService 
{
    @Autowired
    private BusAppointmentMapper busAppointmentMapper;

    /**
     * 查询养修信息预约
     * 
     * @param id 养修信息预约主键
     * @return 养修信息预约
     */
    @Override
    public BusAppointment selectBusAppointmentById(Long id)
    {
        return busAppointmentMapper.selectBusAppointmentById(id);
    }

    /**
     * 查询养修信息预约列表
     * 
     * @param busAppointment 养修信息预约
     * @return 养修信息预约
     */
    @Override
    public List<BusAppointment> selectBusAppointmentList(BusAppointment busAppointment)
    {
        return busAppointmentMapper.selectBusAppointmentList(busAppointment);
    }

    /**
     * 新增养修信息预约
     * 
     * @param busAppointment 养修信息预约
     * @return 结果
     */
    @Override
    public int insertBusAppointment(BusAppointment busAppointment)
    {
        //  1. 首先前台所有的验证后端都要在做一次。也称之为参数合理化验证。也就是前台的6个非空数据我们都要验证。
        if(busAppointment == null){
            throw new RuntimeException("非法参数");
        }
        if(busAppointment.getCustomerName() == null || busAppointment.getCustomerPhone() == null
            || busAppointment.getAppointmentTime() == null || busAppointment.getLicensePlate() == null
            || busAppointment.getCarSeries() == null || busAppointment.getServiceType() == null){
            throw new RuntimeException("非法参数");
        }
        // 	2. 联系方式合理化验证。
        if (!RegexUtils.isPhoneLegal(busAppointment.getCustomerPhone())) {
            throw new RuntimeException("手机号码格式有误");
        }
        // 	3. 车牌号码合理化验证。
        if (VehiclePlateNoUtil.getVehiclePlateNo(busAppointment.getLicensePlate()) == null) {
            throw new RuntimeException("车牌号码格式有误");
        }
        // 	4. 预约时间合理化验证（预约时间需要 > 当前系统时间 1 分钟）。
        // calendar
        Date updateNow = DateUtil.changeDate(new Date(), Calendar.MINUTE, 1);
        if(busAppointment.getAppointmentTime().before(updateNow)){  // 若 预约时间 在 我们修改后的系统时间之前之前
            throw new RuntimeException("预约时间不合法");
        }
        // datetime  方式
        // Date from = Date.from(LocalDateTime.now().plusMinutes(1).atZone(ZoneId.systemDefault()).toInstant());
        // 	5. 关键字段校验。
        // 这些关键字段（例如 status）一般都会存在默认值。
        // 这些默认值一般都不会在数据库中设置，因为我们需要保证数据在进入数据库之前都已经是准确的。
        // 不能等到数据抛异常才发现程序有问题。所以很多时候都在实体类中直接设置默认值。不代表不能在数据库中设置。
        // 也就意味着我们创建这个对象的初期。这些关键字段的默认值就默认存在了。也就是说我们正常不会操作这个字段。
        // 为了安全期间，一般大公司都有一个强制要求，就是前端传入的数据不能直接操作数据库。
        // 因为前端传入的数据本质上我们只需要插入需要用户输入的数据。其他数据都应该是 Null 才对。
        // 一般都会要求新建一个对象。然后把需要用户输入的数据都封装进去。
        // 这种方式就能保证我们插入的数据只有用户输入的那些。
        /*BusAppointment obj = new BusAppointment();
        obj.setCustomerName(busAppointment.getCustomerName());
        obj.setCustomerPhone(busAppointment.getCustomerPhone());
        obj.setAppointmentTime(busAppointment.getAppointmentTime());
        obj.setLicensePlate(busAppointment.getLicensePlate());
        obj.setCarSeries(busAppointment.getCarSeries());
        obj.setServiceType(busAppointment.getServiceType());
        obj.setInfo(busAppointment.getInfo());*/

        // 若不为了扩展，那么存在一种偷懒方式
        busAppointment.setStatus(BusAppointment.STATUS_BOOKING);
        busAppointment.setCreateTime(DateUtils.getNowDate());
        return busAppointmentMapper.insertBusAppointment(busAppointment);
    }

    /**
     * 修改养修信息预约
     * 
     * @param busAppointment 养修信息预约
     * @return 结果
     */
    @Override
    public int updateBusAppointment(BusAppointment busAppointment)
    {
        //  1. 首先前台所有的验证后端都要在做一次。也称之为参数合理化验证。也就是前台的6个非空数据我们都要验证。
        if(busAppointment == null){
            throw new RuntimeException("非法参数");
        }
        if(busAppointment.getCustomerName() == null || busAppointment.getCustomerPhone() == null
                || busAppointment.getAppointmentTime() == null || busAppointment.getLicensePlate() == null
                || busAppointment.getCarSeries() == null || busAppointment.getServiceType() == null){
            throw new RuntimeException("非法参数");
        }
        // 2 3 4 都是用户可能修改的字段，所以使用用户传入的对象进行判定。
        // 	2. 联系方式合理化验证。
        if (!RegexUtils.isPhoneLegal(busAppointment.getCustomerPhone())) {
            throw new RuntimeException("手机号码格式有误");
        }
        // 	3. 车牌号码合理化验证。
        if (VehiclePlateNoUtil.getVehiclePlateNo(busAppointment.getLicensePlate()) == null) {
            throw new RuntimeException("车牌号码格式有误");
        }
        // 	4. 预约时间合理化验证（预约时间需要 > 当前系统时间 1 分钟）。
        // calendar
        Date updateNow = DateUtil.changeDate(new Date(), Calendar.MINUTE, 1);
        if(busAppointment.getAppointmentTime().before(updateNow)){  // 若 预约时间 在 我们修改后的系统时间之前之前
            throw new RuntimeException("预约时间不合法");
        }
        // 5. 状态必须是预约中。
        // 用户是否可以通过非法手段来修改我们的状态？
        // 所以这些不允许用户填写的字段，我们都需要安全验证。
        // 所以我们需要根据 id 将原始对象查询出来
        BusAppointment oldObj = this.selectBusAppointmentById(busAppointment.getId());
        if(oldObj == null){
            throw new RuntimeException("非法参数");
        }
        // 若新对象和老对象的状态若不一致，则说明用户以非法手段修改了我们的数据。
        if(!busAppointment.getStatus().equals(oldObj.getStatus())){
            throw new RuntimeException("非法数据");
        }
        // 在判断用户的状态必须是预约中才可以进行编辑操作
        if (!BusAppointment.STATUS_BOOKING.equals(busAppointment.getStatus())) {
            throw new RuntimeException("状态必须是预约中才可以进行编辑操作");
        }

        return busAppointmentMapper.updateBusAppointment(busAppointment);
    }

    /**
     * 批量删除养修信息预约
     * 
     * @param ids 需要删除的养修信息预约主键
     * @return 结果
     */
    @Override
    public int deleteBusAppointmentByIds(Long[] ids)
    {
        // 当前页面不存在批量选项，所以正常情况下， Long[] ids 数组中应该只有一条数据。
        Long id = ids[0];
        if(id == null){
            throw new RuntimeException("非法参数");
        }
        BusAppointment busAppointment = this.selectBusAppointmentById(id);
        if(busAppointment == null){
            throw new RuntimeException("非法参数");
        }
        // 验证状态
        if(!BusAppointment.STATUS_BOOKING.equals(busAppointment.getStatus())){
            throw new RuntimeException("状态不是预约中的记录禁止删除");
        }
        return busAppointmentMapper.deleteBusAppointmentByIds(ids);
    }

    /**
     * 删除养修信息预约信息
     * 
     * @param id 养修信息预约主键
     * @return 结果
     */
    @Override
    public int deleteBusAppointmentById(Long id)
    {
        return busAppointmentMapper.deleteBusAppointmentById(id);
    }

    /**
     * 到店功能
     * @param id 养修预约主键
     * @return  受影响行数
     */
    @Override
    public int arrival(Long id) {
        // 1. 参数合理化验证
        if (id == null) {
            throw new RuntimeException("非法参数");
        }
        BusAppointment busAppointment = this.selectBusAppointmentById(id);
        if (busAppointment == null) {
            throw new RuntimeException("非法参数");
        }
        // 2. 判断状态必须是预约中才能进行到店操作
        if(!BusAppointment.STATUS_BOOKING.equals(busAppointment.getStatus())){
            throw new RuntimeException("状态必须是预约中的记录才能进行到店操作");
        }
        // 3. 设置 到店时间和更新状态为到店中
        return busAppointmentMapper.changeStatusAndArrivalTimeById(new Date(),BusAppointment.STATUS_ARRIVED,id);
    }

    /**
     * 取消功能
     * @param id 养修预约主键
     * @return  受影响行数
     */
    @Override
    public int cancel(Long id) {
        // 1. 参数合理化验证
        if (id == null) {
            throw new RuntimeException("非法参数");
        }
        BusAppointment busAppointment = this.selectBusAppointmentById(id);
        if (busAppointment == null) {
            throw new RuntimeException("非法参数");
        }
        // 2. 判断状态必须是预约中才能进行到店操作
        if(!BusAppointment.STATUS_BOOKING.equals(busAppointment.getStatus())){
            throw new RuntimeException("状态必须是预约中的记录才能进行到店操作");
        }
        // 3. 设置 到店时间和更新状态为到店中
        return busAppointmentMapper.changeStatusById(BusAppointment.STATUS_USER_CANCELLED,id);
    }

    @Override
    public void updateStatus(Long appointmentId, Integer statusPaid) {
        // 注意参数顺序！！！
        busAppointmentMapper.changeStatusById(statusPaid,appointmentId);
    }
}
